package com.fast.alden.admin.aspect;

import com.fast.alden.admin.annotation.OperationLog;
import com.fast.alden.admin.service.SysOperationLogService;
import com.fast.alden.admin.util.SecurityUtils;
import com.fast.alden.common.util.IpUtils;
import com.fast.alden.common.util.ServletUtils;
import com.fast.alden.data.model.SysOperationLog;
import com.fast.alden.data.model.SysUser;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Aspect
@Component
@Slf4j
public class RecordOperationLog {
    @Resource
    private SysOperationLogService operationLogService;

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(logAnno)")
    public void performOperation(OperationLog logAnno) {

    }

    @Around("performOperation(logAnno)")
    public Object recordOperationLog(ProceedingJoinPoint joinPoint, OperationLog logAnno) throws Throwable {
        SysUser current = SecurityUtils.getCurrentUser();
        long start = System.currentTimeMillis();

        SysOperationLog operationLog = new SysOperationLog();
        operationLog.setTitle(logAnno.title());
        operationLog.setIp(IpUtils.getIpAddr());

        HttpServletRequest request = ServletUtils.getRequest();
        operationLog.setUrl(request.getRequestURI());
        operationLog.setMethod(request.getMethod());
        operationLog.setHandlerMethod(((MethodSignature) joinPoint.getSignature()).getMethod().toString());
        operationLog.setType(logAnno.type());
        operationLog.setOperationTime(LocalDateTime.now());

        operationLog.setUserId(current.getId());
        operationLog.setUsername(current.getUsername());

        try {
            Object ret = joinPoint.proceed();
            operationLog.setSuccess(true);
            return ret;
        } catch (Throwable throwable) {
            operationLog.setSpendTime(System.currentTimeMillis() - start);
            operationLog.setSuccess(false);
            operationLog.setMessage(throwable.getMessage());
            throw throwable;
        } finally {
            operationLog.setSpendTime(System.currentTimeMillis() - start);
            saveOperationLog(operationLog);
        }
    }

    public void saveOperationLog(SysOperationLog operationLog) {
        // 使用虚拟线程保存，跳出原方法的事务管理，如需使用操作系统线程请改为调用ThreadPoolTaskExecutor.execute方法
        Thread.ofVirtual().start(() -> {
            operationLogService.create(operationLog);
        });
    }
}
